package com.hao.tool.common.security;

import com.hao.tool.common.util.JsonKitUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.Base64Codec;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * JSON Web Token
 * Created by haol on 2017/4/20.
 */
public class JwtUtil {


    private Logger logger = LoggerFactory.getLogger(JwtUtil.class);


    public static void main(String[] args) {
        JwtInfo jwtInfo = JwtInfo.build("jti-20200712", "jx-fotc",
                JwtConstant.MONTH_1, null);
        String toke = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MDI0NDkxNTMsInVzZXJuYW1lIjoid2VjaGF0In0.PC6b4fcj8QCCxfFnQTN55JCH-y49sa1bC6UcyIgv1FQ";
        Claims claims = JwtUtil.parseJWT(toke, "mySecret");
        System.out.println(toke);
    }


    /**
     * 生成 jwt 串
     *
     * @param jwtInfo
     * @return
     */
    public static String buildToken(JwtInfo jwtInfo) {
        SecretKey secretKey = generalKey(jwtInfo.getSecret());
        JwtBuilder jwtBuilder = createJwtBuilder(jwtInfo.getJti(), secretKey);
        if (jwtInfo.getExp() != null) {
            jwtBuilder.setExpiration(jwtInfo.getExp());
        }
        jwtBuilder.setIssuedAt(jwtInfo.getIat());
        jwtBuilder.setAudience(jwtInfo.getAud());
        jwtBuilder.setSubject(jwtInfo.getSub());
        jwtBuilder.setIssuer(jwtInfo.getIss());
        jwtBuilder.setNotBefore(jwtInfo.getNbf());
        return jwtBuilder.compact();
    }


    /**
     * 获取 jwt 主题
     *
     * @param jsonWebToken
     * @return
     */
    public static String getSubject(String jsonWebToken) {
        return parseJWT(jsonWebToken, JwtConstant.SECRET).getSubject();
    }


    /**
     * 分析并获取 jwt 内信息
     *
     * @param jwt JSON Web Token
     * @return
     * @throws Exception
     */
    public static Claims analyzeAndGetJWT(String jwt) throws Exception {
        return analyzeAndGetJWT(jwt, JwtConstant.SECRET);
    }


    /**
     * 分析并获取 jwt 内信息
     *
     * @param jwt JSON Web Token
     * @return
     * @throws Exception
     */
    public static Claims analyzeAndGetJWT(String jwt,String secret) throws Exception {
        try {
            if (StringUtils.isBlank(jwt)) {
                throw new NullPointerException("Json Web Token 为空");
            }
            return parseJWT(jwt, secret);
        } catch (NullPointerException e) {
            throw new Exception("验签失败，签名信息不存在");
        } catch (ExpiredJwtException ee) {
            throw new Exception("验签失败，用户签名信息超过有效期");
        } catch (SignatureException se) {
            throw new Exception("验签失败，用户签名信息非法");
        } catch (Exception e) {
            throw new Exception("未知错误，请重新尝试");
        }
    }

    private static SecretKey generalKey(String secret) {
        byte[] encodedKey = Base64Codec.BASE64.decode(secret);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    private static JwtBuilder createJwtBuilder(String jwtId, SecretKey secretKey) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        JwtBuilder jwtBuilder = Jwts.builder();
        jwtBuilder.setHeaderParam("tye", "jwt");
        jwtBuilder.setHeaderParam("alg", "HS256");
        jwtBuilder.setId(jwtId);
        jwtBuilder.signWith(signatureAlgorithm, secretKey);
        return jwtBuilder;
    }

    private static Claims parseJWT(String jwt, String secret) {
        if (StringUtils.isBlank(jwt)) {
            throw new NullPointerException("jwt is empty");
        }
        SecretKey key = generalKey(secret);
        Claims claims = Jwts.parser().setSigningKey(key)
                .parseClaimsJws(jwt).getBody();
        return claims;
    }

    public static String getSubKeyBySub(String subject, String subKey) {
        Map map = JsonKitUtil.getObject(subject, Map.class);
        if (map != null && map.get(subKey) != null) {
            return String.valueOf(map.get(subKey));
        } else {
            return null;
        }
    }

    public static String getSubKeyByToken(String token, String subKey) {
        return getSubKeyBySub(getSubject(token), subKey);
    }

    public static String getTokenValueByCookie(HttpServletRequest request, String name) {
        return CookieUtil.getTokenValueByCookie(request, name);
    }

    public static String getTokenValueByHeader(HttpServletRequest request, String name) {
        String token = request.getHeader(name);
        return token;
    }


}
